/* eslint-disable @typescript-eslint/no-empty-function */
import { cloneDeep } from 'lodash'
import Upload, { Config } from './upload'
import { ElMessage as Message } from 'element-plus'
import api from './http'
import { CONTENT_TYPE_MAP, CONTENT_TYPE_WHITE_LIST, UPLOAD_LIMITED_TYPE } from './constance'

const getSuffix = (url: string) => {
  const cmpUrl = url.split('?')[0]
  const list = cmpUrl.split('.')
  return list[list.length - 1]
}

export const checkImgBySuffix = (url: any) => {
  return CONTENT_TYPE_WHITE_LIST.some((i: any) => i === getSuffix(url))
}

export function transUrl(url: string) {
  if (!url) {
    return url
  }
  const arr = url.split('https://')
  return arr.length > 2 ? `https://${arr[arr.length - 1]}` : url
}

interface FilesMap {
  [key: string]: any
}

// 使用方式参照kf用法

export function Cos(config: Config) {
  let key: string
  let filesMap: FilesMap = {}
  const putUrlMap: any = {}
  const putExtra: any = {
    fname: '',
    params: {},
    mimeType: null
  }
  const { preDomain, useContentType = false } = config
  const _FileUploaded_Handler = config.init && config.init.FileUploaded
  const _Error_Handler = config.init && config.init.Error
  config.init.FileUploaded = function () {}
  config.init.Error = function () {}
  const keyFun = config.init.Key
  const uploader = new Upload(config)
  function getUrlRes(uploader: any, files: any[]) {
    filesMap = {}
    const arr = files.map((file: { name: string | number }) => {
      const req = cloneDeep(uploader.getOption('uptoken_url'))
      const key = keyFun(uploader, file)
      uploader.fileKey = key
      filesMap[file.name] = { key }
      req.data.key = key
      return api({
        method: 'GET',
        params: req
      })
    })
    return Promise.all(arr)
  }
  uploader.init()

  uploader.bind(
    'Error',
    function (
      up: { getOption: (arg0: string) => any; settings: { max_file_size: any }; refresh: () => void },
      err: any
    ) {
      let errTip = ''
      const file = err.file
      if (file) {
        switch (err.code) {
          case Upload.FAILED:
            errTip = '上传失败。请稍后再试。'
            break
          case Upload.FILE_SIZE_ERROR:
            errTip =
              '最大可上传' + (up.getOption && up.getOption('max_file_size')) ||
              (up.settings && up.settings.max_file_size) + '。'
            break
          case Upload.FILE_EXTENSION_ERROR:
            errTip = '文件类型错误，请稍后重试'
            break
          case Upload.HTTP_ERROR:
            if (err.response === '') {
              // Fix parseJSON error ,when http error is like net::ERR_ADDRESS_UNREACHABLE
              errTip = err.message || '未知网络错误。'
              break
            }
            // eslint-disable-next-line no-var
            var errorObj = JSON.parse(err.response)
            // eslint-disable-next-line no-var
            var errorText = errorObj.error
            switch (err.status) {
              case 400:
                errTip = '请求报文格式错误。'
                break
              case 401:
                errTip = '客户端认证授权失败。请重试或提交反馈。'
                break
              case 405:
                errTip = '客户端请求错误。请重试或提交反馈。'
                break
              case 579:
                errTip = '资源上传成功，但回调失败。'
                break
              case 599:
                errTip = '网络连接异常。请重试或提交反馈。'
                break
              case 614:
                errTip = '文件已存在。'
                try {
                  errorObj = JSON.parse(errorObj.error)
                  errorText = errorObj.error || 'file exists'
                } catch (e) {
                  errorText = errorObj.error || 'file exists'
                }
                break
              case 631:
                errTip = '指定空间不存在。'
                break
              case 701:
                errTip = '上传数据块校验出错。请重试或提交反馈。'
                break
              default:
                errTip = '未知错误。'
                break
            }
            errTip = errTip + '(' + err.status + '：' + errorText + ')'
            break
          case Upload.SECURITY_ERROR:
            errTip = '安全配置错误。请联系网站管理员。'
            break
          case Upload.GENERIC_ERROR:
            errTip = '上传失败。请稍后再试。'
            break
          case Upload.IO_ERROR:
            errTip = '上传失败。请稍后再试。'
            break
          case Upload.INIT_ERROR:
            errTip = '网站配置错误。请联系网站管理员。'
            uploader.destroy()
            break
          default:
            errTip = err.message + err.details
            break
        }
        if (_Error_Handler) {
          _Error_Handler(up, err, errTip)
        }
      }
      up.refresh()
    }
  )
  uploader.bind(
    'FilesAdded',
    function (
      uploader: {
        removeFile: (arg0: any) => void
        getOption: (arg0: string) => any
        setOption: (arg0: string, arg1: { 'content-Type': string } | { 'content-Type'?: undefined }) => any
        start: () => void
      },
      files: any[]
    ) {
      if ((config as any).multi_number > 0 && files.length > (config as any).multi_number) {
        Message.error(`同时上传不能超过${config?.multi_number}`)
        files.forEach((file: any) => {
          uploader.removeFile(file)
        })
        return
      }
      const arrType = UPLOAD_LIMITED_TYPE
      const validate = files.find((file: { name: string }) => {
        const arr = file.name.split('.')
        if (arrType.indexOf(arr[arr.length - 1]) !== -1) {
          return true
        }
      })
      if (validate) {
        Message.error('该文件类型禁止上传')
        files.forEach((file: any) => {
          uploader.removeFile(file)
        })
        return
      }

      // 上传之前获取putUrl
      getUrlRes(uploader, files).then((resList) => {
        const cmpList = typeof resList === 'string' ? [resList] : resList
        cmpList.forEach((res, index) => {
          const file = files[index]
          putUrlMap[file.id] = res.putUrl
          file.putUrl = res.putUrl
          const suffix = getSuffix(file.name)
          const contentType = (CONTENT_TYPE_MAP as any)[suffix] || file.type
          uploader.setOption(
            'headers',
            useContentType
              ? {
                  'content-Type': `${contentType};charset=UTF-8`
                }
              : {}
          )
        })
        uploader.start()
      })
    }
  )
  uploader.bind(
    'BeforeUpload',
    function (
      uploader: {
        getOption: (arg0: string) => any
        // eslint-disable-next-line @typescript-eslint/ban-types
        setOption: (arg0: { url: any; multipart: boolean; multipart_params: {} }) => void
        features: { multipart: boolean; chunks: boolean }
      },
      file: { name: string; id: string | number }
    ) {
      // 生成上传标识key值
      key = filesMap[file.name] && filesMap[file.name].key
      if (preDomain) {
        key = `${preDomain}${key}`
      }
      putExtra.params['x:name'] = file.name.split('.')[0]
      // 直接上传
      const directUpload = function () {
        const multipart_params_obj: any = {}
        // filterParams 返回符合自定义变量格式的数组，每个值为也为一个数组，包含变量名及变量值
        const customVarList = Upload.filterParams(putExtra.params)
        for (let i = 0; i < customVarList.length; i++) {
          const k = customVarList[i]
          multipart_params_obj[k[0]] = k[1]
        }
        multipart_params_obj.key = key
        uploader.setOption({
          url: putUrlMap[file.id],
          multipart: true,
          multipart_params: multipart_params_obj
        })
      }
      uploader.features.multipart = false
      uploader.features.chunks = false
      directUpload()
    }
  )

  uploader.bind(
    'FileUploaded',
    function (
      uploader: { refresh: () => void },
      file: { fileKey: any; name: string | number },
      info: { response: any }
    ) {
      file.fileKey = filesMap[file.name] ? filesMap[file.name].key : ''
      uploader.refresh()
      _FileUploaded_Handler(uploader, file, info.response)
    }
  )
  return uploader
}
